package org.ceteca.explica.client;

import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.util.Iterator;

import org.ceteca.explica.client.gui.ExplicaCoreView;
import org.ceteca.explica.client.gui.ExplicaGUIBuilder;
import org.ceteca.explica.client.installer.ClientClasspathUpdater;
import org.ceteca.explica.client.installer.ClientInstaller;
import org.ceteca.explica.core.InterfaceExplica;
import org.ceteca.explica.core.installer.ModuleLauncher;
import org.ceteca.explica.core.installer.ResourceException;
import org.ceteca.javaglade.Gui;
import org.ceteca.javaglade.toolkit.swt.StatusBar;
import org.ceteca.javaglade.toolkit.swt.SwtWidget;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.ProgressBar;
import org.eclipse.swt.widgets.Shell;

public class InitClientOperation extends Thread {
	private Display display;
	private ProgressBar progressBar;
	private Shell initWindow;
	private StatusBar statusBar;
	
	public InitClientOperation(Display display, ProgressBar progressBar, Shell initWindow, StatusBar statusBar) {
		this.display = display;
		this.progressBar = progressBar;
		this.initWindow = initWindow;
		this.statusBar = statusBar;
	}
	
	public void run() {
		display.asyncExec(new UpdateInitProgressBarOperation(progressBar, statusBar, "Explica context initialized"));
		
		if (!ClientContext.getInstance().isReady()) {
			System.err.println("Couldn't configure and initialize the client context! Review log messages for more information.");
			System.err.println("The system cannot continue and will halt now!");
			System.exit(-1);
		}
		
		ClientContext.getInstance().getLogger().
				info("Client application started");
		
		// Check if the resources and modules are up-to-date. If not
		// reinstall their latest versions.
		ClientContext.getInstance().getLogger().
				info("Checking for updates...");
		ClientInstaller.getInstance().configClient(display, progressBar, statusBar, initWindow);
		ClientContext.getInstance().getLogger().
				info("Client application updated!");

		// Create the classloader that will load all the classes used by
		// the client. By using this classLoader instance, the dinamic list 
		// of modules installed in the client is also loaded.
		String classpath = "modules/";

		ClientContext.getInstance().getLogger().
				info("Updating the local classpath with the new installed modules...");
		try {
			ClientClasspathUpdater.addClasspath(classpath);
//			display.asyncExec(new UpdateInitProgressBarOperation(progressBar, statusBar, "Explica classpath updated"));
			
			this.updateProgress(-1, "Explica classpath updated");
		}
		catch (ResourceException ex) {
			ClientContext.getInstance().getLogger().
					error("Error in local classpath updating!", ex);
			System.exit(0 - ex.getErrCode());
		}
		
		ClientContext.getInstance().getLogger().
				info("Initializing the installed modules...");
		// Init all the modules loaded by the client application
		try {
			// Calculate the progress increment for each module (it varies according to
			// the installed modules number and the time spent waiting for the server initialization)
			int progressInc = 1;
			int currentProgress = -1;
			
			GetInitProgressBarOperation getProgressOperation = new GetInitProgressBarOperation(progressBar);
			display.syncExec(getProgressOperation);			
			currentProgress = getProgressOperation.getCurrentProgress();
			
			if (ClientInstaller.getInstance().getModules() != null && ClientInstaller.getInstance().getModules().size() > 0)
				progressInc = (95-currentProgress)/ClientInstaller.getInstance().getModules().size();
			
			System.out.println("CURRENT PROGRES: " + currentProgress + " - PROGRESS INC: " + progressInc + " - " + ClientInstaller.getInstance().getModules().size() + " INSTALLED MODULES");
			
			Iterator it = ClientInstaller.getInstance().getModules().keySet().iterator();
			while (it != null && it.hasNext()) {
				ModuleLauncher modLauncher = ClientInstaller.getInstance().getModules().get(it.next());
				ClientContext.getInstance().getLogger().
						info("Initializing module: " + modLauncher.getModuleData().getName());
				modLauncher.initModule();
//				display.asyncExec(new UpdateInitProgressBarOperation(progressBar, progressInc, statusBar, "Explica module [" + modLauncher.getModuleData().getName() + "] initialized"));
				this.updateProgress(progressInc, "Explica module [" + modLauncher.getModuleData().getName() + "] initialized");
			} // while
		}
		catch (Exception ex) {
			ClientContext.getInstance().getLogger().
					info("Error in module initialization!", ex);
			System.exit(-1);
		}
//		display.asyncExec(new UpdateInitProgressBarOperation(progressBar, statusBar, "Explica installed modules initialized"));
		this.updateProgress(-1, "Explica installed modules initialized");		
		
		// Print the loaded result messages list.
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		PrintStream buf = new PrintStream(bos);
		ClientContext.getInstance().getMsgCatalog().printMessages(buf);
		buf.flush();
		ClientContext.getInstance().getLogger().
			info("-------------- Catalogo de mensajes -------------------\n" +
				 bos.toString() + 
				 "\n-------------------------------------------------------");
		buf.close();
		// display.asyncExec(new UpdateInitProgressBarOperation(progressBar, statusBar, "Explica result messages loaded"));
		this.updateProgress(-1, "Explica result messages loaded");
		
		this.updateProgress(-1, "Explica initialization completed");

		// Build the main window GUI
		ExplicaCoreView.getInstance().setInstalledModules(ClientInstaller.getInstance().getModules());
		display.asyncExec(new BuildGuiOperation(display, progressBar, initWindow, statusBar, ExplicaCoreView.getInstance(), "buildCoreView"));
		this.updateProgress(-1, "Explica main GUI built");
		
		// Build the stack of entity views
		display.asyncExec(new BuildEntityViewOperation(display));
		this.updateProgress(-1, "Explica entity views built");
		
		Gui coreGui = ExplicaGUIBuilder.getInstance().getGui(InterfaceExplica.EXPLICA_CORE_GLADE_NAME);
		ClientContext.getInstance().getLogger().info("Core Gui got " + coreGui);
		
		// Get the parent panel of the main view where the entities will be embedded
		SwtWidget parentPanel = coreGui.getSwtWidget(InterfaceExplica.EXPLICA_MODULE_CONTENTS_PANEL_NAME);
		ClientContext.getInstance().getLogger().info("Parent panel got " + parentPanel + " - " + parentPanel.getWidget());
		
	
		// Close the initializing progress window
		display.asyncExec(new CloseInitializingWindowOperation(this.initWindow));
		
		// Run the test of dinamic module installation
//		Prueba prueba1 = new Prueba();
//		prueba1.run();
	}
	
	public void updateProgress(int progressInc, String statusText) {
		if (progressInc <= 0)
			display.asyncExec(new UpdateInitProgressBarOperation(this.progressBar, this.statusBar, statusText));
		else
			display.asyncExec(new UpdateInitProgressBarOperation(this.progressBar, progressInc, this.statusBar, statusText));
		
		try {
			Thread.sleep(1000);
		} catch (Throwable th) {
		}
	}
}
